import * as turf from '@turf/turf'
import { getVectorContext } from 'ol/render'
import WMarker from './WMarker'
import { decoratePath, fromLonLat, toLonLat, computedAngle, computedPassedIndex, calcNearestPointOnLine } from './utils'

/**
 * 轨迹回放动画对象
 * @param {*} vectorLayer // 图层
 * @param {*} marker // 执行动画的 marker
 * @param {*} type //  marker 对应的源事件
 * @param {*} eventName //  marker对应的动画事件名
 * @param {*} speed // 执行动画的车辆速度
 * @param {*} path	// 执行动画的车辆轨迹坐标数组
 * @param {*} lineFeature // 轨迹祥矢量对象
 * @param {*} circlable	// 是否循环播放
 */

class TrackAnimation {
	constructor(data) {
		const { vectorLayer, type, eventName, marker, speed, path, originalPath, lineFeature, circlable, angleFixed = false } = data
		//初始化 - 动画相关参数配置
		this.status = 'init' // 动画的状态
		this.startPos = null //  动画本次的起点
		this.endPos = null // 动画上次的停止点
		this.distance = 0 // 本次动画进度
		this.lastTime = null // 动画上次执行时间

		this.position = null // 运动矢量图形对象
		this.isArrived = false // 是否到达终点
		this.moveFeature = null // 动画效果函数
		// 初始传入
		this.vectorLayer = vectorLayer // 图层
		this.type = type //  marker 对应的监听事件名
		this.marker = marker // 执行的动画的marker

		this.geoMarker = new WMarker(marker.getOriginOptions()) // 实际执行的动画的marker
		this.eventName = eventName //  marker对应的动画事件名
		this.speed = speed // 行驶速度

		this.path = decoratePath(path) // 执行路径 总路径 10m分割成数组

		this.lineGeometry = lineFeature.getGeometry() // 线条矢量图形对象
		this.circlable = circlable // 是否循环播放

		this.moveCallBack = null //  marker 对应的动画监听回调
		this.proportion = null // 更新进度

		this.iconAngle = this.marker.getOriginOptions().angle || 0 // 图标角度

		this.startAngle = 0 //  动画本次的起点
		this.endAngle = 0 // 动画上次的停止点

		this.passedPath = [] // 目前驶过的总路径
		this.passedPathIndex = 0 // 当前路径索引

		this.originalPath = path // 初始路径
		this.originalIndex = 0 // 初始传入路径索引
		this.originalPassedPath = [] // 初始传入路径驶过路径

		this.angleFixed = angleFixed // marker角度是否随着当前路径不同改变
	}

	//初始化 - 动画对象- 动画准备就绪
	initMove() {
		const isExitMarkerMoveCallBack = this.vectorLayer.animationEvents.has(this.eventName)

		if (isExitMarkerMoveCallBack) {
			const animationEvent = this.vectorLayer.animationEvents.get(this.eventName)
			this.updateMoveCallBack(animationEvent.moveCallBack)
		}

		// 设置当前动画上次执行时间
		this.lastTime = Date.now()
		// 设置上次动画的停止点
		this.endPos = fromLonLat(this.path[0])
		//  动画本次的起点角度
		this.entAngle = this.iconAngle
		// 起点
		this.passedPath.push(this.path[0])
		this.originalPassedPath.push(this.originalPath[0])
		if (this.path.length < 2) return

		// 设置动画效果的执行函数
		this.moveFeature = event => this.moveAnimate(event)
		// 移除动画执行函数
		this.vectorLayer.un('postrender', this.moveFeature)
	}

	//开始 - 重新执行动画
	startMove() {
		// 克隆当前 maker的矢量图形
		this.position = this.marker.getGeometry().clone()
		this.isArrived = false
		// 设置当前动画状态
		this.status = 'moving'
		// this.lastTime = Date.now()

		// 执行动画监听
		this.vectorLayer.on('postrender', this.moveFeature)
		// 隐藏小车前一刻位置同时触发事件

		if (this.marker.WTYPE !== 'OVERLAYMARKER') {
			this.marker.setOpacity(0.01)
		}
		this.marker.setAngle(this.geoMarker.getAngle())
		this.marker.setGeometry(this.position)
	}

	//停止 - 停止执行动画
	stopMove(isPause) {
		// 设置当前动画状态
		this.status = 'stopMove'
		// 回复车辆状态
		this.marker.setOpacity(1)
		// 移除动画监听
		this.vectorLayer.un('postrender', this.moveFeature)
		if (isPause) {
			// 暂停动画最后一次回调
			this.endPos && this.passedPath.push(toLonLat(this.endPos))
			this.dispatchEvent()
		}
	}

	//继续 - 继续执行动画
	resumeMove() {
		if (this.isArrived) return false
		this.lastTime = Date.now()
		this.startMove()
	}

	// 更新速度
	updateSpeed(speed) {
		this.speed = speed
	}

	// 更新进度
	updateDistance(distance) {
		this.proportion = distance
		this.distance = distance
		this.status = 'moving'
		// 计算当前索引值路径
		let index = Math.floor(distance * this.path.length) // 准确值，因为规则分段，每个分段距离一致
		let _index = Math.floor(distance * this.originalPath.length) // 非准确，下面会进行修正原始索引值
		let bearing = 0
		if (distance <= 0) {
			index = 0
			_index = 0
			bearing = 0

			this.isArrived = false

			this.lastTime = Date.now()

			this.endPos = fromLonLat(this.originalPath[_index])

			this.passedPath = [this.originalPath[_index]]

			this.originalPassedPath = [this.originalPath[_index]]

			this.endAngle = bearing + this.iconAngle

			this.marker.setAngle(this.endAngle)

			this.geoMarker.setAngle(this.endAngle)

			this.marker.setPosition(this.originalPath[_index])
		} else if (distance >= 1) {
			index = this.path.length - 1 // 最后一个坐标索引值
			_index = this.originalPath.length - 1 // 最后一个坐标的索引值
			bearing = computedAngle(this.originalPath[_index - 1], this.originalPath[_index])

			this.isArrived = true

			this.passedPath = this.path

			this.originalPassedPath = this.originalPath

			this.endAngle = bearing + this.iconAngle
			// 控制结束位置的marker角度
			if (!this.angleFixed) {
				this.marker.setAngle(this.endAngle)
				this.geoMarker.setAngle(this.endAngle)
			}
			this.marker.setPosition(this.originalPath[_index])
		} else {
			// 根据当前进度获取点位，并且计算除在线段上最近点以及所处index
			let currentCoordinate = this.lineGeometry.getCoordinateAt(distance * 1)
			const { cPoint: oPoint, cIndex: oIndex } = calcNearestPointOnLine(this.originalPath, toLonLat(currentCoordinate)) // 原始路径
			const { cPoint: vPoint, cIndex: vIndex } = calcNearestPointOnLine(this.path, toLonLat(currentCoordinate)) // 虚拟路径
			_index = oIndex
      index = vIndex
			bearing = computedAngle(this.originalPath[_index], this.originalPath[_index + 1])

			this.isArrived = false

			this.originalPassedPath = this.originalPath.slice(0, _index)

			this.endAngle = bearing + this.iconAngle
			// 控制运行过程中的marker角度
			if (!this.angleFixed) {
				this.marker.setAngle(this.endAngle)
				this.geoMarker.setAngle(this.endAngle)
			}
			this.marker.setPosition(vPoint)
		}

		this.passedPathIndex = index
		this.originalIndex = _index
		this.marker.setAngle(this.geoMarker.getAngle())
		this.geoMarker.setAngle(this.geoMarker.getAngle())
		this.stopMove()
	}

	// 动画回调
	updateMoveCallBack(moveCallBack) {
		this.moveCallBack = moveCallBack
	}

	// 到达终点回调
	onArrived() {
		this.isArrived = true
		this.passedPathIndex++
		this.onMoveAnimate()
		this.stopMove()
	}
	//获取当前进度
	getDistance() {
		return this.distance
	}
	// 获取虚拟行驶路径索引
	getMoveIndex() {
		return this.passedPathIndex
	}
	getIndex() {
		return this.originalIndex
	}
	// 派发动画监听回调
	dispatchEvent() {
		if (this.moveCallBack) {
			this.angleFixed = this.marker.angleFixed // 实时改变是否固定角度
			this.marker.olTarget.dispatchEvent({
				progress: this.distance.toFixed(4), // 行驶进度
				pathIndex: this.originalIndex,
				type: this.eventName,
				passedPath: this.originalPassedPath,
				callBack: this.moveCallBack,
				eventName: this.type // 实际派发的事件
			})
		}
	}
	// 动画监听
	onMoveAnimate(currentCoordinate) {
		// 根据索引获取初始驶过路径
		if (this.originalIndex > 0) {
			const originalPassedPath = this.originalPath.slice(0, this.originalIndex + 1)
			const endPos = [this.isArrived ? this.originalPath[this.originalPath.length - 1] : toLonLat(this.endPos)]

			if (currentCoordinate) {
				const { cIndex } = calcNearestPointOnLine(this.originalPath, toLonLat(currentCoordinate))
				this.originalIndex = cIndex > this.originalIndex ? cIndex : this.originalIndex
			}

			this.isArrived && this.originalIndex++

			this.originalPassedPath = originalPassedPath.concat(endPos)
		}

		if (this.passedPathIndex > 0) {
			const index = Math.floor(this.distance.toFixed(4) * this.path.length)
			const currenIndex = index > this.passedPathIndex ? index : this.passedPathIndex
			this.passedPath = this.path.slice(0, currenIndex + 1)
		}
		this.dispatchEvent()
	}
	//执行动画函数
	moveAnimate(event) {
		// 获取当前渲染帧状态时刻
		const time = event.frameState.time
		// 渲染时刻减去开始播放轨迹的时间
		const elapsedTime = time - this.lastTime
		const speed = Number(this.speed)
		// console.log((speed * elapsedTime) / 1e6 + this.distance);
		// 求得距离比
		this.distance = (this.distance + (speed * elapsedTime) / 1e6) % 2
		if (!!this.proportion || this.proportion == 0) {
			this.distance = this.proportion
			this.proportion = null
		}
		// 刷新上一时刻
		this.lastTime = time

		// console.log((speed * elapsedTime) / 1e6);
		if (!this.circlable) {
			if (this.distance >= 1) {
				this.distance = 1
			}
		}

		// 反减可实现反向运动，获取坐标点
		let currentCoordinate = this.lineGeometry.getCoordinateAt(this.distance > 1 ? 2 - this.distance : this.distance)

		this.startPos = this.endPos
		this.endPos = currentCoordinate

		const bearing = computedAngle(this.startPos, this.endPos)

		// 计算虚拟路径驶过索引
		this.passedPathIndex = computedPassedIndex(currentCoordinate, this.path, this.passedPathIndex)
		// 计算驶过路径索引
		this.originalIndex = computedPassedIndex(currentCoordinate, this.originalPath, this.originalIndex)
		if (!this.angleFixed) {
			// 去除停止继续后,startPos，endPos 坐标相同,导致角度为0，闪烁的问题
			if (this.startPos[0] !== this.endPos[0] || this.startPos[1] !== this.endPos[1]) {
				this.startAngle = this.endAngle
				this.endAngle = bearing + this.iconAngle
				this.marker.setAngle(this.endAngle)
				this.geoMarker.setAngle(this.endAngle)
			}
		}
		

		this.marker.setPosition(this.endPos)
		this.geoMarker.setPosition(this.endPos)
		this.position.setCoordinates(this.endPos)

		// 获取渲染图层的画布
		const vectorContext = getVectorContext(event)
		const style = this.geoMarker.getOlStyle()
		this.geoMarker.setGeometry(this.position)

		vectorContext.drawFeature(this.geoMarker, style)

		// 动画监听
		this.onMoveAnimate(currentCoordinate)

		//是否循环
		if (!this.circlable) {
			// 是否到达终点
			if (this.distance >= 1) {
				return this.onArrived()
			}
		}

		// 用来触发Map监听postcompose事件，直到监听事件结束。
		this.vectorLayer.map.render()
	}
}

export default TrackAnimation
